package com.redhat.redwork.widget.tree;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.xwork.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class TreeDataServiceImpl implements TreeDataService {

	@Autowired
	private SessionFactory sessionFactory;
	
	private Log logger = LogFactory.getLog(EntityTreeModelImpl.class);

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public <T extends TreeNode> List<T> loadData(Class<T> clazz,String entityClass, String id,String parentProperty, String idProperty, String textProperty,
			String href) throws Exception{
		
		Object parentValue = null;
		/*
		 * lingen.liu 添加
		 * 
		 * Tree 组件模型中未考虑没有父子关系的实体的树形展示
		 * 
		 * 某些情况下，可能只需要将一些实体以树形的方式显示，这个实体没有父子关系，加入这种情况的考虑
		 * 
		 * 没有父子关系的配置为  idProperty == parentProperty
		 * 
		 * 如果将idProperty 和 parentProperty 设置成一样的，则认为配置的实体没有父子关系，树形结构只在一级的菜单中全部展示
		 */
		
		boolean hasParent = parentProperty.equals(idProperty)?false:true;
		
		
		
		/*
		 * 增加父子关系通过类对象本身关联支持（add by jiangw 2010-04-19）
		 * eg：
		 * public class FunctionEntity{
		 *    //关联父实体
		 *    private FunctionEntity parent;
		 *    
		 * }
		 * 配置parentProperty为parent.id，
		 * 如果id==null，则查询根节点条件：parent is NULL
		 * 否则为parent.id = id
		 */
		
		//父子关系是否通过类对象本身关联
		boolean isObjectAssociation = isObjectAssociation(entityClass, parentProperty.split("\\.")[0]);
		
		
		if(false == isObjectAssociation)
			parentValue = "-1";//默认根节点父节点标识
		
		if (StringUtils.isNotBlank(id)) {
			parentValue = id;
		}
		Session session = sessionFactory.openSession();
		
		List<T> treeNodes = new ArrayList<T>();
		try {
			
			Query query = null;
			Class<?> entity = Class.forName(entityClass);
		 if(hasParent){
			
			String hql = "from " + entity.getName() + " c where c.";
			
			//父子关系通过类对象本身关联
			if(parentValue==null){
				query = session.createQuery(hql.concat(parentProperty.split("\\.")[0] + " is NULL"));
			}else{//父子关系通过类对象主键关联
				query = session.createQuery(hql.concat(parentProperty+" = :parentValue"));
				if (sessionFactory.getClassMetadata(entity).getPropertyType(
						parentProperty) instanceof org.hibernate.type.IntegerType) {
					parentValue = Integer.valueOf(parentValue.toString());
				}
				if (sessionFactory.getClassMetadata(entity).getPropertyType(
						parentProperty) instanceof org.hibernate.type.LongType) {
					parentValue = Long.valueOf(parentValue.toString());
				}

				query.setParameter("parentValue", parentValue);
			}

			List<?> objs = query.list();
			
			if (objs != null && objs.size() > 0) {

				hql = "select count(*) " + hql.concat(parentProperty + " = :parentValue");
				
				Query q = session.createQuery(hql);
				
				for (Object obj : objs) {
				
					BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
					Object textValue = beanWrapper.getPropertyValue(textProperty);
					Object idValue = beanWrapper.getPropertyValue(idProperty);

					T node = clazz.newInstance();

					if (textValue != null) {
						// 节点的文字
						node.setText(textValue.toString());
					}
					
					
					if (idValue != null) {
						
						String thref = href;

						if(StringUtils.isNotBlank(thref)){
							if(thref.indexOf("?") != -1){
								thref = thref+"&id="+idValue.toString();
							}else{
								thref = thref +"?id="+idValue.toString();
							}
						}

						// URL链接
						node.setHref(thref);
						
						// 节点ID
						node.setId(idValue.toString());

						q.setParameter("parentValue", idValue);

						// 是否叶子节点
						Long childsize = (Long) q.uniqueResult();
						node.setLeaf(childsize>0?false:true);

					}

					treeNodes.add(node);

				}
			}
		}
		/*
		 * lingen.liu添加，实体不存在父子关系的时候，查出所有实体，以树形的方式展现
		 */
		else{
			String hql = "from " + entity.getName();
			query = session.createQuery(hql);
			List<?> objs = query.list();
			
			if (objs != null && objs.size() > 0) {
				
				for (Object obj : objs) {
					
					BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
					Object textValue = beanWrapper.getPropertyValue(textProperty);
					Object idValue = beanWrapper.getPropertyValue(idProperty);
					
					T node = clazz.newInstance();
					
					if (textValue != null) {
						// 节点的文字
						node.setText(textValue.toString());
						
						if (idValue != null) {
							
							String thref = href;

							if(StringUtils.isNotBlank(thref)){
								if(thref.indexOf("?") != -1){
									thref = thref+"&id="+idValue.toString();
								}else{
									thref = thref +"?id="+idValue.toString();
								}
							}

							// URL链接
							node.setHref(thref);
							
							// 节点ID
							node.setId(idValue.toString());

							// 是否叶子节点
							node.setLeaf(true);

						}

						treeNodes.add(node);
					}
					
				}
				
			}
			
			}

		} catch (Exception e) {
			logger.error(e);
			throw e;
			
		} finally {
			if (session != null)
				session.close();
		}

		return treeNodes;
	}
	
	/**
	 * 判断父子关系是否通过类对象本身关联
	 * @param className
	 * @param filedName
	 * @return
	 */
	public boolean isObjectAssociation(String className,String filedName){
		try {
			Class<?> clazz = Class.forName(className);
			
			Field field = clazz.getDeclaredField(filedName);
			String genericType = field.getGenericType().toString().split("\\s")[1];
			
			return className.equals(genericType);
			
		} catch (Exception e) {
			return false;
		}
	}

}
